package com.lanhai.agv.dispatch;

import java.util.List;

import com.lanhai.agv.Tools;
import com.lanhai.agv.cache.AgvCache;
import com.lanhai.agv.cache.EventLockCache;
import com.lanhai.agv.cache.AgvItem;
import com.lanhai.agv.cache.EstimateCache; 
import com.lanhai.agv.cache.MountCache;
import com.lanhai.agv.cache.ParkCache;
import com.lanhai.agv.cache.ParkItem;
import com.lanhai.agv.cache.ParkRelationCache;
import com.lanhai.agv.cache.ParkTypeEnum;
import com.lanhai.agv.cache.ReadyDotCache;
import com.lanhai.agv.cache.ReadyDotItem;
import com.lanhai.agv.cache.RoadCache;
import com.lanhai.agv.cache.StationGroupCache;
import com.lanhai.agv.cache.TranfficAreaCache;
import com.lanhai.agv.log.LogData;
import com.lanhai.agv.log.LogQueue;
import com.lanhai.agv.push.MsgData;
import com.lanhai.agv.push.MsgQueue;
import com.lanhai.agv.queue.AgvEventUnit;
import com.lanhai.agv.queue.DispatchQueue;
import com.lanhai.agv.queue.DispatchUnit;
import com.lanhai.agv.queue.TargetCmdEnum;

/**
 * agv上报消息分析处理
 * 
 * @author virus408
 *
 */
public class AgvResolve {

	/**
	 * 解析消息
	 * 
	 * @param unit
	 */
	public static void Resolve(AgvEventUnit unit) {
		AgvData data = getData(unit.getData());
		if (data == null) {
			// 数据解析失败
			return;
		}

		AgvItem agv = AgvCache.getAgvByIP(unit.getIp());
		if (agv == null) {
			// 对应的小车不存在
			return;
		}
		switch (data.getType()) {
		case BZ:
			//// 避障 nothing
			break;
		case CD:
			//// 充电 nothing
			break;
		case DD:
			//// 到达
			if (EventLockCache.lock(unit.getIp(), data.getCmdStr()) == false) {
				// 只需要处理一次，强行return，防止括号内容过长
				return;
			}
			Log(data, unit.getIp());
			// 更新小车位置
			AgvCache.updateAgvInfo(unit.getIp(), data.getX(), data.getY(), data.getRoad(), true);
		 
			// 判断是否到主路
			if (data.getRoad() == 0) {
				//// 回到主路成功
				// 走装卸工位的路由路线
				ParkItem tmp = ParkCache.getParkByNo(agv.getParkNo());
				if (tmp != null) { 
					AgvToRoad(agv, tmp.getTargetRoad());

					// 释放小车的装卸工位，但是设备分组不做释放
					ParkCache.setAgv(agv.getParkNo(), "");
				}

				return; // 结束操作，不考虑后面的到达停泊位
			}

			//// 到达停泊位
			int lv=RoadCache.getLv(agv.getRoadid()); 
			ParkItem park = ParkCache.getParkByPos(data.getX(), data.getY(),lv);
			if (park == null) {
				 
				// 到达了一个表中不存在的停泊位，这是一个数据BUG
				return;
			}
			// 更新小车当前的所在的停泊位
			AgvCache.arrivedPark(agv.getIP(), park.getParkNo());
			// 更新停泊位上的小车
			ParkCache.setAgv(park.getParkNo(), agv.getIP());
			//保存状态
			AgvCache.saveState(agv.getAgvId());
			
			
			//// 开始处理停泊位的各种类型
			if (park.getType() == ParkTypeEnum.Power) {
				//// 充电点，判断是否需要充电
			} else if (park.getType() == ParkTypeEnum.Wait) {
				//// 待命点，不处理

			} else if (park.getType() == ParkTypeEnum.Trans) {
				//// 可传输工位， 更新小车的装载情况。具体的传输操作交给小车的“可传输”去处理

				// 更新装卸情况
				AgvMountState mobj = new AgvMountState();
				mobj.setFinishReceive(false);
				mobj.setFinishSend(false);
				mobj.setDownFull(data.isDownFull());
				mobj.setUpFull(data.isUpFull());
				MountCache.mountAgv(agv.getAgvId(), unit.getIp(), mobj);

				// 释放小车占用的停泊位
				ReadyDotCache.removeAgv(park.getParkNo(), agv.getAgvId());

				// 通知预判断点释放一两小车
				int sourceDot = StationGroupCache.getReadySource(park.getParkNo());
				if (sourceDot == 0) return; 
				DispatchUnit dus = new DispatchUnit();
				dus.setFromAgv(true);
				dus.setIp(unit.getIp());
				dus.setPort(0);
				dus.setParkNo(sourceDot);
				dus.setTarget(TargetCmdEnum.NoticeEstimate);
				DispatchQueue.Push(dus);

				return;

			} else if (park.getType() == ParkTypeEnum.TransReady) {
				//// 装卸分配工位
				// 1.如果来源是待命位的（分配去了待命点）
				if (ReadyDotCache.isFromDot(park.getParkNo(), agv.getAgvId())) {
					// 小车的下道工序对应的设备分组名称
					List<String> stationGroupList = StationGroupCache.getCanUseStationGroup(agv.getNextProcess());
					// 优选一个设备分组
					ParkItem one = ParkCache.getCanTransPark(stationGroupList, park.getSelectType());
					if (one == null) {
						// 待命位回归分配工位时没有可用设备，原因只有一种：对接工位出了问题
						// 极小概率发生，让小车停止
						AgvStopOrStart(agv, true);
					} else {
						// 锁该设备分组
						StationGroupCache.lockGroup(one.getProcessGroup(), one.getStationGroup(), agv.getIP());
						// 小车去装卸工位 ，待命点位释放放在到达传输位
						AgvToRoad(agv, one.getTargetRoad());
					}
					// 后续的不用操作了
					return;
				}

				// 2.如果来源是预判断点来的
				if (ReadyDotCache.isEmpty(park.getParkNo(), agv.getNextProcess())) {
					// 待命点全空，可以先判断对接设备组
					List<String> stationGroupList = StationGroupCache.getCanUseStationGroup(agv.getNextProcess());
					ParkItem toTrans = ParkCache.getCanTransPark(stationGroupList, park.getSelectType());
					if (toTrans == null) {
						// 没有可用的对接设备，进入待命点
						ReadyDotItem dmd = ReadyDotCache.getEmptyDotItem(park.getParkNo());
						if (dmd == null) {
							// 没有可用的待命点，调度数据出现了错误,
							EventLockCache.lock(unit.getIp(), "");
							return;
						}
						// 分配待命点
						ReadyDotCache.dispathDot(agv.getAgvId(), park.getParkNo());
						// 让小车去待命点
						AgvToRoad(agv, dmd.getSourceRoad());
					} else {
						// 把对应的设备分组锁住
						StationGroupCache.lockGroup(toTrans.getProcessGroup(), toTrans.getStationGroup(), agv.getIP());
						// 分配小车路线
						AgvToRoad(agv, toTrans.getSourceRoad());

					}
				} else {
					// 待命点有小车,让小车去待命点
					ReadyDotItem dmd = ReadyDotCache.getEmptyDotItem(park.getParkNo());
					if (dmd == null) {
						// 没有可用的待命点，调度数据出现了错误,
						EventLockCache.lock(unit.getIp(), "");
						return;
					}
					// 分配待命点
					ReadyDotCache.dispathDot(agv.getAgvId(), park.getParkNo());
					// 让小车去待命点
					AgvToRoad(agv, dmd.getSourceRoad());
				}
			} else if (park.getType() == ParkTypeEnum.TransOut) {
				//// 释放工位
				// 解锁小车对应的设备分组
				StationGroupCache.unlockForAgv(agv.getIP());

				// 触发装卸分配工位的释放事件 :点位及对应的工序
				int readyParkNo = ParkRelationCache.getReadyDotParkNoByEstimate(park.getParkNo());
				String processName = StationGroupCache.getProcessNameByAgvIp(agv.getIP());

				DispatchUnit dus = new DispatchUnit();
				dus.setFromAgv(true);
				dus.setIp(unit.getIp());
				dus.setPort(0);
				dus.setParkNo(readyParkNo);
				dus.setProcessName(processName);
				dus.setTarget(TargetCmdEnum.NoticeReadyDot);
				DispatchQueue.Push(dus);

				// 执行后面的路线
				AgvToRoad(agv, park.getTargetRoad());

			} else if (park.getType() == ParkTypeEnum.Estimate) {
				//// 进入了预判断点
				int targetParkNo=ParkRelationCache.getReadyDotParkNoByEstimate(park.getParkNo());
				 if(targetParkNo<=0) return;
				if (ReadyDotCache.hasDot(targetParkNo, agv.getNextProcess())) { 
					// 如果前方有待命点，则移动过去
					int troad=ParkCache.getTargetRoad(targetParkNo);
					AgvToRoad(agv, troad);
				} else {
					// 没有，则小车停下来，并进入野车队列
					EstimateCache.stopAgv(targetParkNo , agv.getAgvId());
					AgvStopOrStart(agv, true);
				}
			}
			break;
		case DM:
			// 待命 nothing
			if (EventLockCache.lock(unit.getIp(), data.getCmdStr())) { 	
				//保存状态
				AgvCache.saveState(agv.getAgvId());
			}
			break;
		case JG:
			// 交管 
			if (EventLockCache.lock(unit.getIp(), data.getCmdStr())) { 	
				//保存状态
				AgvCache.saveState(agv.getAgvId());
			}
			break;
		case JT:
			// 急停
			if (EventLockCache.lock(unit.getIp(), data.getCmdStr())) {
				Log(data, unit.getIp());
				AgvCache.updateAgvInfo(unit.getIp(), data.getX(), data.getY(), data.getRoad(), true);
				
				//保存状态
				AgvCache.saveState(agv.getAgvId());
			}
			break;
		case KCS:
			// 可传输,
			if (EventLockCache.lock(unit.getIp(), data.getCmdStr())) {
				Log(data, unit.getIp());

				ParkItem pk = ParkCache.getParkByAgv(unit.getIp());
				if (pk == null)
					return;
				if (pk.isNeedIn() == false && pk.isNeedOut() == false) {
					// 不允许传输，不处理
					EventLockCache.lock(unit.getIp(), "");
					return;
				}

				// 申请调度
				DispatchUnit dus = new DispatchUnit();
				dus.setFromAgv(true);
				dus.setIp(unit.getIp());
				dus.setPort(0);
				dus.setTarget(TargetCmdEnum.Judgement);
				DispatchQueue.Push(dus);
			}
			break;
		case LX:
			// 离线
			if (EventLockCache.lock(unit.getIp(), data.getCmdStr())) {
				Log(data, unit.getIp());
				AgvCache.abnormal(unit.getIp());
				
				//保存状态
				AgvCache.saveState(agv.getAgvId());
			}
			break;
		case SCCW:
		case SCRW:
		case SCXRW:
		case SRCW:
		case SRRW:
		case SRXCW:
		case SZCW:
		case SZRW:
		case XCCW:
		case XCRW:
		case XRCW:
		case XRRW:
		case XZCW:
		case XZRW:
			// 各种传输完成，交给调度处理
			// if (EventLockCache.lock(unit.getIp(), data.getCmdStr())) {
			
			//保存传输状态
			
			//调度
			Log(data, unit.getIp());
			DispatchUnit du = new DispatchUnit();
			du.setFromAgv(true);
			du.setIp(unit.getIp());
			du.setPort(0);
			du.setTarget(TargetCmdEnum.Judgement);
			DispatchQueue.Push(du);
			// }
			break;
		case ZXWC:
			// 装卸完成
			break;
		case TZ:
			// 停止
			// AgvCache.updateAgvInfo(unit.getIp(), data.getX(), data.getY(), true);
			if (EventLockCache.lock(unit.getIp(), data.getCmdStr())) {
				Log(data, unit.getIp());
				AgvCache.abnormal(unit.getIp());
				
				//保存状态
				AgvCache.saveState(agv.getAgvId());
			}
			break;
		case ERR:
			// 异常了
			if (EventLockCache.lock(unit.getIp(), data.getCmdStr())) {
				Log(data, unit.getIp());
				AgvCache.abnormal(unit.getIp());
				
				//保存状态
				AgvCache.saveState(agv.getAgvId());
			}
			break;
		case XS:
			// 行驶中
			AgvCache.updateAgvInfo(unit.getIp(), data.getX(), data.getY(), data.getRoad(), false);
			Log(data, unit.getIp());

			int areaID = TranfficAreaCache.intoArea(data.getX(), data.getY());
			if (areaID > 0) {
				if (agv.getAreaId() == areaID)
					return;
				if (TranfficAreaCache.isService(areaID)) {
					//// 进入了故障服务区
					AgvCache.clearSource(unit.getIp());
					return;
				}

				// 进入交管区
				AgvCache.updateAreaId(unit.getIp(), areaID); 
				if (TranfficAreaCache.lockArea(areaID, agv.getAgvId())) {
					// 锁住区域成功,更新当前区域id  继续前进  
				} else {
					// 需要停下来
					TranfficAreaCache.addStopAgv(areaID, agv.getAgvId()); 

					// 向小车发送停车的指令
					AgvStopOrStart(agv, true);
				}
			} else {
				// 离开交管区,下一步操作交给leaveArea中去判断
				if (agv.getAreaId() > 0) {
					AgvCache.leaveArea(unit.getIp()); 
				}
			}
			
			//保存状态
			AgvCache.saveState(agv.getAgvId());
			
			break;
		default:
			break;

		}
	}

	/**
	 * 小车的指令解析
	 * 
	 * @param buf
	 * @return
	 */
	static AgvData getData(byte[] buf) {
		if (buf.length < 13) {
			return null;
		}
		// 只处理来自小车的数据
		if (buf[0] != 0xA1) {
			return null;
		}
		AgvData obj = new AgvData();
		if (buf[9] == 1) {
			// 小车异常
			obj.setType(AgvReceiveEnum.ERR);
			return obj;
		}

		obj.setType(AgvReceiveEnum.getAgvReceiveEnumByCode(buf[2]));
		if (buf[11] == 0x00) {
			// 全空
			obj.setUpFull(false);
			obj.setDownFull(false);
		} else if (buf[11] == 0x01) {
			// 上空下满
			obj.setUpFull(false);
			obj.setDownFull(true);
		} else if (buf[11] == 0x10) {
			// 上满下空
			obj.setUpFull(true);
			obj.setDownFull(false);
		} else if (buf[11] == 0x11) {
			// 全满
			obj.setUpFull(true);
			obj.setDownFull(true);
		}
		obj.setPower(buf[10]);
		obj.setRoad(buf[3]);
		obj.setAgvId(buf[1]);
		byte[] gpX = { buf[5], buf[6], 0, 0 };
		byte[] gpY = { buf[7], buf[8], 0, 0 };
		obj.setX(Tools.toIntL(gpX));
		obj.setY(Tools.toIntL(gpY));
		obj.setCmdStr(Tools.byte2HexStr(buf));
		obj.setData(buf);
		return obj;
	}

	/**
	 * 生成日志并写进队列里
	 * 
	 * @param data
	 * @param ip
	 */
	static void Log(AgvData data, String ip) {
		LogData logobj = LogData.fromAgv(data, ip);
		LogQueue.Push(logobj);
	}

	public static void AgvToRoad(AgvItem agv, int road) {
		if (agv == null || road<0)
			return;
		MsgData msg = new MsgData(agv.getIP(), agv.getPort(), AgvCmd.runRoad(agv.getAgvId(), road),
				String.format("启动路线%s", road));
		msg.setAgvId(agv.getAgvId());
		MsgQueue.Push(msg);
	}

	public static void AgvStopOrStart(AgvItem agv, boolean stop) {
		if (agv == null)
			return;
		String rmark="交管停车";
		if(stop==false) {
			rmark="交管启动";
		}
		MsgData stopCmd = new MsgData(agv.getIP(), agv.getPort(), AgvCmd.stopOrstart(agv.getAgvId(), stop), rmark);
		stopCmd.setAgvId(agv.getAgvId());
		MsgQueue.Push(stopCmd);
	}
}
